﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MoroMoro.Tools.DDDProjector
{
    public sealed class SolutionCreator
    {
        private static readonly string[] ReplacementTargetExtensions = new string[]
        {
            ".sln",
            ".csproj",
            ".cs",
            ".tt",
            ".xml",
            ".settings",
            ".config",
            ".shfbproj",
            ".content",
            ".aml",
        };


        public SolutionCreator(string destinationDirectoryPath, IParameters parameters)
        {
            _destinationDirectoryPath = destinationDirectoryPath;
            _parameters = parameters;
            _baseApplicationGuid = Guid.NewGuid();
            _mainApplicationGuid = Guid.NewGuid();
            _basePersistenceGuid = Guid.NewGuid();
            _mainPersistenceGuid = Guid.NewGuid();
            _baseDomainGuid = Guid.NewGuid();
            _mainDomainGuid = Guid.NewGuid();
        }


        private readonly string _destinationDirectoryPath;
        private readonly IParameters _parameters;
        private readonly Guid _baseApplicationGuid;
        private readonly Guid _mainApplicationGuid;
        private readonly Guid _basePersistenceGuid;
        private readonly Guid _mainPersistenceGuid;
        private readonly Guid _baseDomainGuid;
        private readonly Guid _mainDomainGuid;


        public DirectoryInfo Create()
        {
            const string sourceDirectoryPath = @".\Source";

            CopyDirectory(sourceDirectoryPath, _destinationDirectoryPath);

            var solutionDirectoryPath = Path.Combine(_destinationDirectoryPath, "DDDSolutionName");
            var solutionDirectory = new DirectoryInfo(solutionDirectoryPath);
            try
            {
                ReplaceParameters(solutionDirectory);
            }
            catch
            {
                solutionDirectory.Delete(true);
                throw;
            }

            return solutionDirectory;
        }

        private void CopyDirectory(string sourceDirectoryPath, string destinationDirectoryPath)
        {
            if (!Directory.Exists(destinationDirectoryPath))
            {
                Directory.CreateDirectory(destinationDirectoryPath);
            }

            var sourceDirectory = new DirectoryInfo(sourceDirectoryPath);

            var sourceChildDirectories = sourceDirectory.GetDirectories();
            foreach (var sourceChildDirectory in sourceChildDirectories)
            {
                var destinationChildDirectoryPath = Path.Combine(destinationDirectoryPath, sourceChildDirectory.Name);
                CopyDirectory(sourceChildDirectory.FullName, destinationChildDirectoryPath);
            }

            var sourceChildFiles = sourceDirectory.GetFiles();
            foreach (var sourceChildFile in sourceChildFiles)
            {
                var destinationChildFilePath = Path.Combine(destinationDirectoryPath, sourceChildFile.Name);
                File.Copy(sourceChildFile.FullName, destinationChildFilePath);
            }
        }

        private void ReplaceParameters(DirectoryInfo directory)
        {
            var newDirectoryName = ReplaceParameter(directory.Name);
            if (!string.Equals(directory.Name, newDirectoryName, StringComparison.Ordinal))
            {
                var newDirectoryPath = Path.Combine(directory.Parent.FullName, newDirectoryName);
                directory.MoveTo(newDirectoryPath);
            }

            var childDirectories = directory.GetDirectories();
            foreach (var childDirectory in childDirectories)
            {
                ReplaceParameters(childDirectory);
            }

            var childFiles = directory.GetFiles();
            foreach (var childFile in childFiles)
            {
                if (!FileIsReplacementTarget(childFile))
                {
                    continue;
                }

                var newName = ReplaceParameter(childFile.Name);
                if (!string.Equals(childFile.Name, newName, StringComparison.Ordinal))
                {
                    var newFullName = Path.Combine(directory.FullName, newName);
                    childFile.MoveTo(newFullName);
                }

                var contents = File.ReadAllText(childFile.FullName, Encoding.UTF8);
                var newContents = ReplaceParameter(contents);
                File.WriteAllText(childFile.FullName, newContents, Encoding.UTF8);
            }
        }

        private string ReplaceParameter(string text)
        {
            var builder = new StringBuilder(text);
            builder.Replace("DDDSolutionName", _parameters.DDDSolutionName);
            builder.Replace("$registeredorganization$", _parameters.OrganizationName);
            builder.Replace("$year$", DateTime.Now.Year.ToString());
            builder.Replace("BaseApplicationProjectName", _parameters.BaseApplicationProjectName);
            builder.Replace("BaseApplicationAssemblyName", _parameters.BaseApplicationAssemblyName);
            builder.Replace("BaseApplicationNamespace", _parameters.BaseApplicationNamespace);
            builder.Replace("BaseApplicationGuid", _baseApplicationGuid.ToString());
            builder.Replace("MainApplicationProjectName", _parameters.MainApplicationProjectName);
            builder.Replace("MainApplicationAssemblyName", _parameters.MainApplicationAssemblyName);
            builder.Replace("MainApplicationNamespace", _parameters.MainApplicationNamespace);
            builder.Replace("MainApplicationGuid", _mainApplicationGuid.ToString());
            builder.Replace("BasePersistenceProjectName", _parameters.BasePersistenceProjectName);
            builder.Replace("BasePersistenceAssemblyName", _parameters.BasePersistenceAssemblyName);
            builder.Replace("BasePersistenceNamespace", _parameters.BasePersistenceNamespace);
            builder.Replace("BasePersistenceGuid", _basePersistenceGuid.ToString());
            builder.Replace("MainPersistenceProjectName", _parameters.MainPersistenceProjectName);
            builder.Replace("MainPersistenceAssemblyName", _parameters.MainPersistenceAssemblyName);
            builder.Replace("MainPersistenceNamespace", _parameters.MainPersistenceNamespace);
            builder.Replace("MainPersistenceGuid", _mainPersistenceGuid.ToString());
            builder.Replace("BaseDomainProjectName", _parameters.BaseDomainProjectName);
            builder.Replace("BaseDomainAssemblyName", _parameters.BaseDomainAssemblyName);
            builder.Replace("BaseDomainNamespace", _parameters.BaseDomainNamespace);
            builder.Replace("BaseDomainGuid", _baseDomainGuid.ToString());
            builder.Replace("MainDomainProjectName", _parameters.MainDomainProjectName);
            builder.Replace("MainDomainAssemblyName", _parameters.MainDomainAssemblyName);
            builder.Replace("MainDomainNamespace", _parameters.MainDomainNamespace);
            builder.Replace("MainDomainGuid", _mainDomainGuid.ToString());
            return builder.ToString();
        }

        private bool FileIsReplacementTarget(FileInfo file)
        {
            return ReplacementTargetExtensions.Any(item => string.Equals(item, file.Extension.Trim(), StringComparison.OrdinalIgnoreCase));
        }
    }
}
